﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;

using System.Data.Common;

using RAD.LightOne.Properties;

namespace RAD.LightOne.Data
{
    #region Documentation
    /// <summary>
    /// Classe que provê informações específicas de configuração o ProviderFactory/Banco de dados utilizado.
    /// Singleton.
    /// </summary>
    #endregion
    internal sealed class Configuration
    {
        #region Fields

        const char SPLITTER = ';';

        private static Configuration instance;

        private  string parameterPrefix;

        private  string factoryName;

        private  Type factoryType;

        private  SqlCaseTransform transform;

        private string schemaPrefix;

        #endregion

        #region Properties

        #region Documentation
        /// <summary>
        /// O prefixo substitui o mnemônico '$' nas expressões SQL passadas ou geradas pelo framework.
        /// </summary>
        #endregion
        public  string ParameterPrefix
        {
            get { return parameterPrefix; }
        }

        public string QuotePrefix
        {
            get;
            private set;
        }

        public string QuoteSuffix
        {
            get;
            private set;
        }

        public  string FactoryName
        {
            get { return factoryName; }
        }

        #region Documentation
        /// <summary>
        /// Define o prefixo para o nome de uma tabela, normalmente o "schema" ao qual a mesma pertence.
        /// </summary>
        #endregion
        public string SchemaPrefix
        {
            get { return schemaPrefix; }
        }


        public  Type FactoryType
        {
            get { return factoryType; }
        }


        public  SqlCaseTransform Transform
        {
            get { return transform; }
        }

        #endregion

        #region Methods

        internal static Configuration Initialize(DbProviderFactory factory)
        {
            if (instance == null)
            {
                instance = new Configuration(factory);
            }

            return instance;
        }

        internal static Configuration Instance()
        {
            if (instance == null) throw new InvalidProgramException("Configuration don't initialized, call Initialize function first.");
            return instance;
        }

        #endregion

        #region Constructors

        private Configuration(DbProviderFactory factory)
        {
            factoryName = factory.GetType().Name;
            factoryType = factory.GetType();
            
            List<string> paramKeys = new List<string>();
            paramKeys.AddRange(ConfigurationManager.AppSettings.AllKeys);

            switch (factory.GetType().Name)
            {
                case "SqlClientFactory":
                    this.parameterPrefix = Settings.Default.SqlServerPrefix;
                    this.QuotePrefix = Settings.Default.SqlServerQuote.Split(SPLITTER)[0];
                    this.QuoteSuffix = Settings.Default.SqlServerQuote.Split(SPLITTER)[1];
                    break;
                case "MySqlClientFactory":
                    this.parameterPrefix = Settings.Default.MySqlPrefix;
                    this.QuotePrefix = Settings.Default.MySqlQuote.Split(SPLITTER)[0];
                    this.QuoteSuffix = Settings.Default.MySqlQuote.Split(SPLITTER)[1];
                    break;
                case "OdbcClientFactory":
                    this.parameterPrefix = Settings.Default.OdbcPrefix;
                    this.QuotePrefix = Settings.Default.OdbcQuote.Split(SPLITTER)[0];
                    this.QuoteSuffix = Settings.Default.OdbcQuote.Split(SPLITTER)[1];
                    break;
                case "OracleClientFactory":
                    this.parameterPrefix = Settings.Default.OraclePrefix;
                    this.QuotePrefix = Settings.Default.OracleQuote.Split(SPLITTER)[0];
                    this.QuoteSuffix = Settings.Default.OracleQuote.Split(SPLITTER)[1];
                    break;
                default:
                    DbCommandBuilder builder = factory.CreateCommandBuilder();
                    this.parameterPrefix = Settings.Default.DefaultPrefix;
                    this.QuotePrefix = builder.QuotePrefix;
                    this.QuoteSuffix = builder.QuoteSuffix;
                    break;
            }

            //customizações definidas no arquivo de config devem sobrepor aos parâmetros predefinidos.
            if (paramKeys.Contains("CustomParameterPrefix")) parameterPrefix = ConfigurationManager.AppSettings["CustomParameterPrefix"];
            if (paramKeys.Contains("CustomQuoteStart"))    this.QuotePrefix = ConfigurationManager.AppSettings["CustomQuoteStart"];
            if (paramKeys.Contains("CustomQuoteEnd"))    this.QuoteSuffix = ConfigurationManager.AppSettings["CustomQuoteEnd"];
            if (paramKeys.Contains("SchemaPrefix")) this.schemaPrefix = ConfigurationManager.AppSettings["SchemaPrefix"];

            if (paramKeys.Contains(typeof(SqlCaseTransform).Name))
            {
                try
                {
                    transform = (SqlCaseTransform)Enum.Parse(typeof(SqlCaseTransform), ConfigurationManager.AppSettings[typeof(SqlCaseTransform).Name]);
                }
                catch (Exception except)
                {
                    throw new ConfigurationErrorsException(string.Format("{0} key is wrong.", typeof(SqlCaseTransform).Name), except);
                }
            }
            else
            {
                transform = SqlCaseTransform.None;
            }
        }
   

        #endregion
    }
}
